package com.ruoyi.gams.device.led;

import com.ruoyi.gams.device.led.LEDSender2010;
import com.ruoyi.gams.device.led.MyUdpSocket;

import java.util.ArrayList;
import java.util.List;
//import java.util.Calendar;

public class WanService {

    static int MAX_REPORT_COUNT = 1024;

    static private final int STATUS_NONE = 0;
    static private final int STATUS_READY = 1;
    static private final int STATUS_DONE = 2;
    static private final int STATUS_TIMEOUT = 3;

    static public final int R_EXECUTE = 0;
    static public final int R_BUSY = 1;
    static public final int R_OFFLINE = 2;

    static public final int TASK_COMMAND = 1;
    static public final int TASK_DATA = 2;

    private class Reporter {
        public String m_report_name;
        public String m_report_ip;
        public int m_report_port;
        public long m_report_tick;
    }

    private class ReportCB {
        private long m_report_timeo = 60000;
        private List<Reporter> m_report_list = new ArrayList<Reporter>();

        //public int get_report_count(){
        //	return m_report_list.size();
        //}

        public String get_report_name(int index) {
            if (index >= 0 && index < m_report_list.size()) {
                return m_report_list.get(index).m_report_name;
            } else {
                return "";
            }
        }

        public String get_report_ip(int index) {
            if (index >= 0 && index < m_report_list.size()) {
                return m_report_list.get(index).m_report_ip;
            } else {
                return "";
            }
        }

        public int get_report_port(int index) {
            if (index >= 0 && index < m_report_list.size()) {
                return m_report_list.get(index).m_report_port;
            } else {
                return 6666;
            }
        }

        public int find_report_name(String name) {
            int i;
            for (i = 0; i < m_report_list.size(); i++) {
                if (m_report_list.get(i).m_report_name.equals(name)) {
                    return i;
                }
            }
            return -1;
        }

        public void add(String name, String ip, int port) {
            int k;
            Reporter reporter = new Reporter();
            m_report_list.add(reporter);
            k = m_report_list.size() - 1;
            m_report_list.get(k).m_report_name = name;
            m_report_list.get(k).m_report_ip = ip;
            m_report_list.get(k).m_report_port = port;
            m_report_list.get(k).m_report_tick = System.currentTimeMillis() + m_report_timeo;
        }

        public int parse_heart(byte[] packet, int size, String ip, int port) {
            String name;
            int k;
            if (size >= LEDSender2010.HEART_STRUCT_SIZE && LEDSender2010.asInt(packet, LEDSender2010.HEART_FLAG_OFFSET) == 0x55AA55AA) {
                name = LEDSender2010.asString(packet, LEDSender2010.HEART_NAME_OFFSET);
                System.out.println("接收到心跳包：Size=" + size + " name=" + name + " ip=" + ip + " port=" + port);
                k = find_report_name(name);
                if (k < 0) {
                    add(name, ip, port);
                } else {
                    m_report_list.get(k).m_report_name = name;
                    m_report_list.get(k).m_report_ip = ip;
                    m_report_list.get(k).m_report_port = port;
                    m_report_list.get(k).m_report_tick = System.currentTimeMillis() + m_report_timeo;
                }
                return k;
            }
            return -1;
        }

        public void process_message() {
            int i = 0;
            while (i < m_report_list.size()) {
                if (System.currentTimeMillis() > m_report_list.get(i).m_report_tick) {
                    System.out.println("设备<" + m_report_list.get(i).m_report_name + ">离线");
                    m_report_list.remove(i);
                } else i++;
            }
        }

        public ReportCB(long report_timeo) {
            m_report_timeo = report_timeo;
        }
    }

    private class TaskCB {
        private int m_action;
        private int m_command;
        private int m_addr;
        private int m_tx_timeo;
        private int m_tx_repeat;
        private int m_repeat;
        private long m_tick;
        private int m_state;
        private int m_serialno;

        public String m_remote_host;
        public int m_remote_port;
        public String m_name;
        public LEDSender2010 m_ledsender;
        public byte m_packet[];
        public int m_packet_size;

        public void parse_respond(byte[] packet, int size) {
            switch (m_action) {
                case TASK_COMMAND: //表示命令
                    if (m_ledsender.parse_cmd_respond(packet, size) == 1) {
                        m_state = 1;
                    }
                    break;
                case TASK_DATA: //表示数据
                    switch (m_ledsender.parse_trans_respond(packet, size, m_command, m_serialno)) {
                        case 1:
                            if (m_command == LEDSender2010.PKC_END) {
                                m_state = 1;
                            } else {
                                m_serialno++;
                                m_repeat = 0;
                                m_tick = 0;
                            }
                            break;
                        case 2:
                            m_serialno = m_ledsender.fix_serialno;
                            m_command = LEDSender2010.PKC_DATA;
                            m_repeat = 0;
                            m_tick = 0;
                            break;
                    }
                    break;
            }
        }

        public int process_message() {
            if (m_state == 0) {
                switch (m_action) {
                    case TASK_COMMAND: //表示命令
                        if (System.currentTimeMillis() > m_tick) {
                            if (m_repeat == 0) {
                                m_packet_size = m_ledsender.GetDataSize();
                                LEDSender2010.blockCopy(m_packet, 0, m_ledsender.data_stream, 0, m_packet_size);
                            }
                            if (m_repeat < m_tx_repeat) {
                                m_tick = System.currentTimeMillis() + m_tx_timeo;
                                m_repeat++;
                                return STATUS_READY;
                            } else {
                                return STATUS_TIMEOUT;
                            }
                        }
                        return 0;
                    case TASK_DATA: //表示数据
                        if (System.currentTimeMillis() > m_tick) {
                            if (m_repeat < m_tx_repeat) {
                                m_tick = System.currentTimeMillis() + m_tx_timeo;
                                m_repeat++;
                                if (m_serialno == 0) {
                                    m_command = LEDSender2010.PKC_BEGIN;
                                    m_packet_size = m_ledsender.pkg_begin(m_packet, m_addr);
                                } else if (m_serialno == m_ledsender.get_pkg_count(512) + 1) {
                                    m_command = LEDSender2010.PKC_END;
                                    m_packet_size = m_ledsender.pkg_end(m_packet, m_addr, m_serialno);
                                } else {
                                    m_command = LEDSender2010.PKC_DATA;
                                    m_packet_size = m_ledsender.pkg_data(m_packet, m_addr, m_serialno, 512);
                                }
                                return STATUS_READY;
                            } else {
                                return STATUS_TIMEOUT;
                            }
                        }
                        return STATUS_NONE;
                }
                return STATUS_NONE;
            } else {
                return STATUS_DONE;
            }
        }

        public TaskCB(int action, int command, int addr, byte[] buffer, int size, int tx_timeo, int tx_repeat) {
            m_ledsender = new LEDSender2010(buffer, size);
            m_action = action;
            m_command = command;
            m_addr = addr;
            m_tx_timeo = tx_timeo;
            m_tx_repeat = tx_repeat;
            m_serialno = 0;
            m_repeat = 0;
            m_packet = new byte[1280];
            m_packet_size = 0;
            m_state = 0;
        }
    }

    private MyUdpSocket m_udp;
    private ReportCB m_rcb = new ReportCB(60000);
    private List<TaskCB> m_task_list = new ArrayList<TaskCB>();

    public static void mysleep(int msec) {
        try {
            Thread.sleep(msec);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //发送UDP包，buffer为发送数据，size为发送数据长度
    private void udp_send(LEDSender2010 ledsender, byte[] buffer, int size, String host, int port) {
        byte[] packet = new byte[size];
        LEDSender2010.blockCopy(packet, 0, buffer, 0, size);
        //System.out.println("发送：");
        //ledsender.print_stream(packet, size);
        try {
            m_udp.send(host, port, packet, size);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    //接收UDP包，buffer为接收数据，size为接收数据长度
    private int udp_receive(byte[] buffer) {
        int size = 0;
        int k, x;
        size = m_udp.receive();
        if (size > 0) {
            m_udp.get_receive_packet(buffer, size);
            //如果是心跳包，按照心跳包直接处理
            k = m_rcb.parse_heart(buffer, size, m_udp.get_client_ip(), m_udp.get_client_port());
            if (k >= 0) {
                //System.out.println("收到心跳包");
                //System.out.println("Name=" + m_rcb.get_report_name(k));
                //System.out.println("IP=" + m_rcb.get_report_ip(k));
                //System.out.println("Port=" + m_rcb.get_report_port(k));
                x = FindXcb(m_rcb.get_report_name(k));
                if (x >= 0) {
                    m_task_list.get(x).m_remote_host = m_rcb.get_report_ip(k);
                    m_task_list.get(x).m_remote_port = m_rcb.get_report_port(k);
                }
                //心跳包时，表示不是协议应答包，返回0
                size = 0;
            }
        }
        return size;
    }

    public int FindXcb(String host, int port) {
        int i;
        TaskCB tcb;
        for (i = 0; i < m_task_list.size(); i++) {
            tcb = m_task_list.get(i);
            if (tcb.m_remote_host.equals(host) && tcb.m_remote_port == port) {
                return i;
            }
        }
        return -1;
    }

    public int FindXcb(String name) {
        int i;
        for (i = 0; i < m_task_list.size(); i++) {
            if (m_task_list.get(i).m_name.equals(name)) {
                return i;
            }
        }
        return -1;
    }

    public int AddTask(String name, int action, int command, int addr, byte[] buffer, int size) {
        int k, x, r;
        TaskCB tcb;

        k = m_rcb.find_report_name(name);
        if (k >= 0) {
            x = FindXcb(name);
            if (x < 0) {
                tcb = new TaskCB(action, command, addr, buffer, size, 1000, 10);
                tcb.m_remote_host = m_rcb.get_report_ip(k);
                tcb.m_remote_port = m_rcb.get_report_port(k);
                tcb.m_name = name;
                m_task_list.add(tcb);
                r = R_EXECUTE;
            } else {
                r = R_BUSY;
            }
        } else r = R_OFFLINE;

        return r;
    }

    public WanService(int loc_port) {
        try {
            m_udp = new MyUdpSocket(loc_port);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        //m_rcb.add("led", "192.168.2.99", 6666);
    }

    @Override
    protected void finalize() {
        try {
            m_udp.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        m_udp = null;
    }

    public void execute() {
        int size, k, i;
        byte[] packet = new byte[2048];
        TaskCB tcb;

        m_rcb.process_message();
        size = udp_receive(packet);
        while (size > 0) {
            k = FindXcb(m_udp.get_client_ip(), m_udp.get_client_port());
            if (k >= 0) {
                //System.out.println("接收：");
                //m_task_list.get(k).m_ledsender.print_stream(packet, size);
                m_task_list.get(k).parse_respond(packet, size);
            }
            size = udp_receive(packet);
        }

        i = 0;
        while (i < m_task_list.size()) {
            tcb = m_task_list.get(i);
            switch (tcb.process_message()) {
                case STATUS_READY:    //有数据要发送
                    udp_send(tcb.m_ledsender, tcb.m_packet, tcb.m_packet_size, tcb.m_remote_host, tcb.m_remote_port);
                    i++;
                    break;
                case STATUS_DONE: //通讯完成
                    System.out.println(tcb.m_name + "：任务执行完成");
                    tcb = null;
                    m_task_list.remove(i);
                    break;
                case STATUS_TIMEOUT: //通讯超时
                    System.out.println(tcb.m_name + "：任务超时");
                    tcb = null;
                    m_task_list.remove(i);
                    break;
                default:
                    i++;
                    break;
            }
        }
        tcb = null;
    }
}
